package hooks

import (
	"context"
	"fmt"
	"io"
	"os"

	log "atomgit.com/atomgit_dev/alog/alogcore"
	"atomgit.com/atomgit_dev/git-hooks/pkg/config"
	"atomgit.com/atomgit_dev/git-hooks/pkg/internal/agitext"
	"atomgit.com/atomgit_dev/git-hooks/pkg/stream"
	pb "atomgit.com/atomgit_dev/satellite-proto/go"
)

// StartPreSendPack calls satellite.PreSendPackHook to execute pre-send-pack hook.
func StartPreSendPack(ctx context.Context) (int, error) {
	return preSendPack(ctx, config.PreSendPackOpt, os.Stdout, os.Stderr)
}

func preSendPack(ctx context.Context, opt config.PreSendPackOption, stdout, stderr io.Writer) (int, error) {
	repository, err := agitext.GetPbRepositoryFromEnv()
	if err != nil {
		return 1, fmt.Errorf("fail to extract pb.Repository from env: %w", err)
	}

	log.Info(ctx, "begin to execute pre-send-pack hook",
		log.NewField("RepositoryID", repository.GlRepositoryId),
		log.NewIntField("have", int(opt.Have)),
		log.NewIntField("filter", int(opt.Filter)),
		log.NewIntField("depth", int(opt.Depth)),
	)

	conn, err := getSatelliteConn()
	if err != nil {
		return 1, fmt.Errorf("fail to create grpc client for pre-send-pack: %w", err)
	}
	defer conn.Close()

	// Using PreReceiveTimeout as timeout
	ctx, cancel := context.WithTimeout(ctx, config.Cfg.PreReceiveTimeout)
	defer cancel()
	preSendPackStream, err := pb.NewHookServiceClient(conn).PreSendPackHook(ctx, &pb.PreSendPackHookRequest{
		Repository:           repository,
		Have:                 opt.Have,
		Filter:               opt.Filter,
		Depth:                opt.Depth,
		EnvironmentVariables: os.Environ(),
	})
	if err != nil {
		return 1, fmt.Errorf("fail to get pre-send-pack hook: %w", err)
	}

	returnCode, err := stream.Handler(func() (stream.StdoutStderrResponse, error) {
		return preSendPackStream.Recv()
	}, func(errC chan error) { errC <- nil }, stdout, stderr)
	if err != nil {
		log.WithError(err).Error(ctx, "error receiving data for pre-send-pack hook")
		return 1, err
	}
	return int(returnCode), nil
}
